#include "../includes.h"


KernalInfo_		KernalInfo;

OSC_			OSC;


OCXO_ID_		OCXO_ID;

ID_Table_		IDTable;
fTempTable_	fIDTable[MAX_ID_TABLE_SIZE];



void GetTempDAC(void);
char read_temp_id(void);

void Init_OCXO_ID(void);

void Init_OSC(void)
{

	if(IsRbModel()){
		OSC.kind = Rubidium_OSC;
		WarmupTimeCounter = 5*60;
	}
	else {
		OSC.kind = OCXO_OSC;
		WarmupTimeCounter = 7*60;
	}

	OSC.exist = YES;

	Init_OCXO_ID();
}


//============================================================================================
//OCXO
//============================================================================================

void Init_OCXO_ID(void)
{

	OCXO_ID.Valid = NO;
	OCXO_ID.TDAC = 0;

	OCXO_ID.id_str[0] = 'X';
	OCXO_ID.id_str[1] = (char)0;

	OCXO_ID.Buffer_flag = OFF;
}


void Setting_OCXOID(void)
{
	char result;

	result = read_temp_id();
	if( result == OK ){
		OCXO_ID.mode = (char)IDTable.mode;
   		OCXO_ID.Buffer_flag = ON;
		OCXO_ID.Valid = YES;
	}
	else {
		OCXO_ID.Valid = NO;
		if( 1 ){
			OCXO_ID.mode = ID_MODE_SLOPE;
			OCXO_ID.Valid = YES;
		}
	}
}


void swap_table(int index)
{
	IDTable.Table[index].Temperature = 
		(IDTable.Table[index].Temperature << 16 & 0xFFFF0000) | (IDTable.Table[index].Temperature >> 16 & 0x0000FFFF);
	IDTable.Table[index].Yintercept = 
		(IDTable.Table[index].Yintercept << 16 & 0xFFFF0000) | (IDTable.Table[index].Yintercept >> 16 & 0x0000FFFF);
	IDTable.Table[index].Slope = 
		(IDTable.Table[index].Slope << 16 & 0xFFFF0000) | (IDTable.Table[index].Slope >> 16 & 0x0000FFFF);
	
}

char id_mode = 0;

#define SwapByte(x) ( (((x)>>8)&0xFF) | (((x)<<8)&0xFF00) )
#define SwapByteL(x) ( (((x)>>24)&0x000000FF) | (((x)<<24)&0xFF000000)|(((x)>>8)&0x0000FF00) | (((x)<<8)&0x00FF0000) )
#define SwapEach(x,y) do{ temp=x; x=y; y=temp; }while(0);

char read_temp_id()
{
    FILE *fp;
	int i;
    char temp;
    register unsigned short *S_ADDR;
	unsigned short CRC16;
	
	WORD test;
	
	fp = fopen("/gpsclock/34833_tid.bin", "rb");
	
	if( fp == NULL ){
		//printf( "Open Error... /gpsclock/34833_tid.bin\n");
		
		OCXO_ID.Buffer_flag = ON;
        
   		IDTable = *(ID_Table_ *)OCXO_ID.Buffer;
		
		//kang if( !strcmp(CONFIG.OCXO_ID,IDTable.NAME) && IDTable.TableNo > 0 && IDTable.TableNo < 16 ) {
		if( IDTable.TableNo > 0 && IDTable.TableNo < 16 ) {
			for( i = 0; i < IDTable.TableNo; i++ ){
				swap_table(i);
				IDTable.mode = ID_MODE_DAC;
				fIDTable[i].Temperature = ((double)100/(double)16) /(double)100.0;
				fIDTable[i].Yintercept 	= 0;
				fIDTable[i].Slope 	= 0;
			}
		}
		//return OK;
		return NO;
	}
	
	//printf("fp = %p\n", fp);

	fread(&KernalInfo, sizeof(KernalInfo), 1, fp);
	
	//for(i=0; i<127; i++){  //127
	//	printf("fp = %X\n", KernalInfo.data[i]);
	//}	
	
	//printf("KernalInfo.CRC16 = %X\n",KernalInfo.CRC16);
	
	CRC16 = CheckCRC16( (BYTE*)&KernalInfo.data[0], 254 );
	
	//printf("CRC16=%X\n",CRC16);
	
	
	//fclose(fp);
	//return;
	
	
	if(KernalInfo.CRC16 == CRC16)
	{
 
   		for(i = 0; i < 6; i++){
    		//OCXO_ID.Buffer[i] = KernalInfo.data[i+PC_PROGRAM_HEADER];
			OCXO_ID.Buffer[i] = KernalInfo.data[i];
			//printf("OCXO_ID.Buffer[%d]=%X\n",i,OCXO_ID.Buffer[i]);
    	}
		

    	for(i = 6; i < 127; i++){
    		//OCXO_ID.Buffer[i] = (KernalInfo.data[i+PC_PROGRAM_HEADER]>>8 & 0x00FF) | (KernalInfo.data[i+PC_PROGRAM_HEADER]<<8 & 0xFF00); //swap
			OCXO_ID.Buffer[i] = (KernalInfo.data[i]>>8 & 0x00FF) | (KernalInfo.data[i]<<8 & 0xFF00); //swap
			//printf("OCXO_ID.Buffer[%d]=%X\n",i,OCXO_ID.Buffer[i]);
    	}

    	
   		//fclose(fp);
		//return;
		
		OCXO_ID.Buffer_flag = ON;
        
   		IDTable = *(ID_Table_ *)OCXO_ID.Buffer;
		
   		//printf("IDTable NAME: %s\n", IDTable.NAME);
		//printf("IDTable mode: %d\n", IDTable.mode);
		//printf("IDTable table num: %d\n", IDTable.TableNo);
		
		//for(i=0;i<12;i++){
		//	printf("CONFIG.OCXO_ID:%c\n",CONFIG.OCXO_ID[i]);
		//}
		
		//for(i=0;i<12;i++){
		//	printf("IDTable.NAME:%c\n",IDTable.NAME[i]);
		//}
		
		//printf("IDTable.mode:%X\n",IDTable.mode);
		//printf("IDTable.TableNo:%d\n",IDTable.TableNo);
		
		//kang if( !strcmp(CONFIG.OCXO_ID,IDTable.NAME) && IDTable.TableNo > 0 && IDTable.TableNo < 16 ) {
		if( IDTable.TableNo > 0 && IDTable.TableNo < 16 ) {
	    	for( i = 0; i < IDTable.TableNo; i++ ){
				
				//printf("Enter~\n");
				
	    		swap_table(i);
	    		
				if (IDTable.mode == ID_MODE_FREQ) {
					fIDTable[i].Temperature = IDTable.Table[i].Temperature /(float)DEC_Temperature;
    				fIDTable[i].Yintercept 	= IDTable.Table[i].Yintercept / (double)DEC_Intercept;
    				fIDTable[i].Slope 		= IDTable.Table[i].Slope / (double)DEC_Slope;
					
					//printf("ID_MODE_FREQ~\n");
					//printf("Temperature:%f, Yintercept:%f, Slope:%f",fIDTable[i].Temperature,fIDTable[i].Yintercept,fIDTable[i].Slope);
    			}
    			else if(IDTable.mode == ID_MODE_DAC || IDTable.mode == ID_MODE_CURRENT){
					fIDTable[i].Temperature = IDTable.Table[i].Temperature /100.0;
    				fIDTable[i].Yintercept 	= IDTable.Table[i].Yintercept / 100.0;
    				fIDTable[i].Slope 		= IDTable.Table[i].Slope / 100.0;
					
					//printf("Temperature:%f, Yintercept:%f, Slope:%f",fIDTable[i].Temperature,fIDTable[i].Yintercept,fIDTable[i].Slope);
    			}
    			else {
    				return FAIL;
    			}
    		}
			
			//fclose(fp);
			//return;
			
    		if(IDTable.mode == ID_MODE_FREQ) id_mode = ID_MODE_FREQ;
			//kang else if(IDTable.mode == ID_MODE_DAC || IDTable.mode == ID_MODE_CURRENT) id_mode = ID_MODE_CURRENT;
    		else if(IDTable.mode == ID_MODE_DAC) id_mode = ID_MODE_DAC;
			else if(IDTable.mode == ID_MODE_CURRENT) id_mode = ID_MODE_CURRENT;
			
			fclose(fp);
			
			return OK;
		}
	}
	//sprintf(MESG,"ID:%s TableNO:%d\r\n", IDTable.NAME, IDTable.TableNo);
	//TransmitMessage((BYTE*)MESG,DEBUG_PORT);
	
	return FAIL;
}


void GetTempDAC()
{
	int i;
	int index;

	//printf(">>>%d, %d,%d \n", OCXO_ID.Valid ,CONFIG.TEMPER_CONTROL ,OCXO_ID.mode);

	if( OCXO_ID.Valid == NO || CONFIG.TEMPER_CONTROL == NO ) return;

//	if( OSC.kind == OCXO_OSC ){

		index = 0;

		if( OCXO_ID.mode == ID_MODE_DAC ){

			if( TEMPERATURE.AVERAGE < fIDTable[0].Temperature ) {
				index = 0;
			}
			else if ( TEMPERATURE.AVERAGE >= fIDTable[IDTable.TableNo-1].Temperature ) {
				index = IDTable.TableNo-1;
			}
			else {
		   		for( i = 0; i < IDTable.TableNo-1; i++ ) {
		   			if( (fIDTable[i].Temperature <= TEMPERATURE.AVERAGE ) && ( TEMPERATURE.AVERAGE < fIDTable[i+1].Temperature) ){
						index = i;
					}
				}
			}

		}
		else if(OCXO_ID.mode == ID_MODE_CURRENT ){

			if( TEMPERATURE.current_average < fIDTable[0].Temperature ) {
				index = 0;
			}
			else if ( TEMPERATURE.current_average >= fIDTable[IDTable.TableNo-1].Temperature ) {
				index = IDTable.TableNo-1;
			}
			else {
		   		for( i = 0; i < IDTable.TableNo-1; i++ ) {
		   			if( (fIDTable[i].Temperature <= TEMPERATURE.current_average ) && ( TEMPERATURE.current_average < fIDTable[i+1].Temperature) ){
						index = i;
					}
				}
			}
		}


		if( OCXO_ID.mode == ID_MODE_FREQ ){
	   		OCXO_ID.TDAC = -(fIDTable[index].Yintercept + fIDTable[index].Slope * (double)TEMPERATURE.AVERAGE)/KGainF;
	   	}
		else if( OCXO_ID.mode == ID_MODE_DAC ){
	   		OCXO_ID.TDAC = (fIDTable[index].Yintercept + fIDTable[index].Slope * (double)TEMPERATURE.AVERAGE);
		}
		else if( OCXO_ID.mode == ID_MODE_CURRENT ){
	   		OCXO_ID.TDAC = (fIDTable[index].Yintercept + fIDTable[index].Slope * (double)TEMPERATURE.current_average);
	   	}
		else if( OCXO_ID.mode == ID_MODE_SLOPE ){
	   		OCXO_ID.TDAC = ( ((double)CONFIG.iTemperatureGain)/100.) * (double)(TEMPERATURE.AVERAGE-25);
	   		//printf(">>>%d * %d = %d \n", (int)(CONFIG.iTemperatureGain/100),(int)(TEMPERATURE.AVERAGE-25),  (int)(OCXO_ID.TDAC)  );

	   	}



//	}
//	else {
//		OCXO_ID.TDAC = (40.0 - TEMPERATURE.AVERAGE) * 0.4666;
//		index = 99;
//	}
    sprintf(OCXO_ID.id_str,"[%02d]",index);
    //sprintf((char*)MESG,"<%.2f>",TEMPERATURE.AVERAGE);
    //MessageOut(MESG);

}

//////////////////////////////////
//////////////////////////////////
//////////////////////////////////
//////////////////////////////////
//////////////////////////////////
//// Get Temperature in Lock Condition...
/// Maybe the same as holdover caculation..
/// but I want to make independant routinue  2011.04.03 by through

stTGain_ TempGain = {1, };

void TGainPushEach(int t, int T, int dac, int offset)
{
	stTGainData_ d;
	d.t = t;
	d.T = T;
	d.dac = dac;
	d.offset = offset;
	TGainPush(&d);
}
void TGainPush(stTGainData_ *pp)
{
	stTGain_ *p=&TempGain;
	if( p->first ){ // only once
		p->first = 0; p->i=0; p->cnt=0;
		p->Tmin			= p->Tmax 		= pp->T;
		p->OFFSETmin 	= p->OFFSETmax	= pp->offset;
		p->dPrev = *pp;
		return;
	}
	if( (pp->t - p->dPrev.t) < M_stTGainData_Interval-1 ) return; // to keep the data gathering interval to over 50sec.
	if( iLsiDebugVariable == 52 ) printf("TGainPush>> %d-%d=%d"
			", dac:%5d, T:%d O:%d"
			"(%5d,%5d)\r\n"
			,pp->t ,p->dPrev.t ,(pp->t - p->dPrev.t)
			,pp->dac, pp->T, pp->offset
			,p->i,p->cnt
			);
	// save data to array
	p->d[p->i]= *pp;

	// inc. index & rollover index
	p->cnt++; p->i++;
	if( p->i >= M_stTGainData_Size) p->i = 0;
	p->dPrev = *pp;

	// get min, max
	if( pp->T < p->Tmin ) p->Tmin = pp->T;
	if( pp->T > p->Tmax ) p->Tmax = pp->T;
	if( pp->offset < p->OFFSETmin ) p->OFFSETmin = pp->offset;
	if( pp->offset > p->OFFSETmax ) p->OFFSETmax = pp->offset;
}

int bTGainDisply = 0;
int sTGainDisply = 0;
int iTGainDisply = 0;

int TGainDisplay()
{
	stTGain_ *p=&TempGain;
	int i=0;
	//int s; // start

	if( !bTGainDisply ){
		if( p->cnt > M_stTGainData_Size ){ // get start pos.. in advance
			sTGainDisply = p->i+1;
			sTGainDisply = sTGainDisply%M_stTGainData_Size;
		}
		else sTGainDisply = 0;
		iTGainDisply=0;
		return 0;
	}

	if( p->cnt< 1){ bTGainDisply=0; printf("no data\n"); return 0; }

	//printf("\r\n");
	while( sTGainDisply != p->i && i < 5 ){
		printf(
				"%d,(%5d),%6d,), "
				"%2d ,%5d, %3de-9 "
				"\r\n"
				,iTGainDisply++, sTGainDisply ,p->d[sTGainDisply].t
				,p->d[sTGainDisply].T ,p->d[sTGainDisply].dac ,p->d[sTGainDisply].offset
		);
		sTGainDisply++;
		i++;
		sTGainDisply = sTGainDisply%M_stTGainData_Size;
	}

	if( sTGainDisply == p->i )
	{
		bTGainDisply = 0;
		printf("------ T( min:%d ,max:%d ) Offset( min:%d ,max:%d )-----\n"
				,p->Tmin, p->Tmax ,p->OFFSETmin,p->OFFSETmax);

		TGainCalc(0);

		printf("\r\n");
		return 1;
	}
	return 0;
}
void TGainCalc(int apply)
{
	stTGain_ *p=&TempGain;
	double x[M_stTGainData_Size],y[M_stTGainData_Size];
	double a,b;
	int s, cnt;
	if( p->cnt< 1){ printf("no data\n"); return;}
	if( p->Tmax - p->Tmin < 1 ){ printf("Calc error:Tmax(%d)-Tmin(%d)<1 \n",p->Tmax,p->Tmin); return; }

	// get start position
	if( p->cnt > M_stTGainData_Size ){
		s = p->i+1;
		s = s%M_stTGainData_Size;
	}
	else s = 0;

	//calc
	cnt = 0;
	while( s != p->i && cnt <= M_stTGainData_Size){
		x[cnt] = p->d[s].T; y[cnt] = p->d[s].dac;
		s++;
		s = s%M_stTGainData_Size;
		cnt++;
	}

	if( cnt-1 < 3) printf("size error\n");
	filter_get_linear_fit( x, y, cnt-1, &a, &b);
	printf("cnt:%d\n",cnt);
	p->TGain = (int)(b*100);
	printf("DAC = %.3f*T %+d\n""TGain:%d\n", b,(int)a, p->TGain);
	if( apply ){
		if( p->Tmax - p->Tmin < 3 ){ printf("Calc error:Tmax(%d)-Tmin(%d)<1 \n",p->Tmax,p->Tmin); return; }
		printf("TGain before:%dE-100-->",(int)CONFIG.iTemperatureGain);
		CONFIG.iTemperatureGain = p->TGain+CONFIG.iTemperatureGain;
		printf("TGain after: %dE-100\n""Apply OK!\n",(int)CONFIG.iTemperatureGain);
		CONFIG.WriteEvent = ON;
	}

}
